import hmac
import json
import requests
import urllib.parse as urlparse
import hashlib
import sys
import time

from coin.exchange.base.kr_rest.auth_base import AuthKey
from coin2.api_client.common import (SyncQueryer)
from enum import Enum

class Side(Enum):
  BUY = "BUY"
  SELL = "SELL"

class Type(Enum):
  LIMIT = "LIMIT"
  MARKET = "MARKET"
  STOP = "STOP"
  TAKE_PROFIT = "TAKE_PROFIT"
  STOP_MARKET = "STOP_MARKET"
  TAKE_PROFIT_MARKET = "TAKE_PROFIT_MARKET"
  TRAILING_STOP_MARKET = "TRAILING_STOP_MARKET"

class TimeInForce(Enum):
  GTC = "GTC"
  IOC = "IOC"
  FOK = "FOK"
  GTX = "GTX"

class ApolloxAuth(requests.auth.AuthBase):
  def __init__(self, key):
    self._key = AuthKey.from_file(key)

  def _gen_signature(self, query: str, body: str):
    before_signature = ''.join(filter(None, [query, body])).encode()
    signature = hmac.new(self._key.secret_key_bytes, before_signature, digestmod=hashlib.sha256)
    return signature.hexdigest()

  def __call__(self, req: requests.PreparedRequest):
    req.prepare_url(req.url, {'timestamp': int(time.time() * 1000)})

    req.headers.update({'X-MBX-APIKEY': self._key.access_key})
    req.prepare_headers(req.headers)

    signature = self._gen_signature(urlparse.urlparse(req.url).query, req.body)
    req.prepare_url(req.url, {'signature': signature})

    # print(req.headers)
    # print(req.body)
    # print(req.url)

    return req

class ApolloxPrivateClient():
  def __init__(self, key_path: str, ip=None):
    self._auth = ApolloxAuth(key_path)
    self._url = "https://fapi.apollox.finance"

    self._query = SyncQueryer(api_host=self._url, auth=self._auth, ip=ip)

  def submit_order(
    self, symbol: str,
    side: Side,
    type: Type,
    time_in_force: TimeInForce,
    quantity: str = None,
    price: str = None,
    stop_price: str = None,
    callback_rate: str = None,
  ):
    assert symbol, "symbol must be not None and not empty!"
    assert side, "side must be not None!"
    assert type, "type must be not None!"
    assert time_in_force, "time_in_force must be not None!"

    method = "POST"
    params = {
      'symbol': symbol,
      'side': side.value,
      'type': type.value,
      'quantity': quantity,
      'price': price,
      'stopPrice': stop_price,
      'callbackRate': callback_rate,
      'timeInForce': time_in_force.value,
    }
    self._path = "/fapi/v1/order"

    response = self._query.query(method=method, path=self._path, params=params)
    return response.json()

  def cancel_order(self, symbol: str, order_id: int = None, orig_client_order_id: str = None):
    assert symbol, "symbol must be not None and not empty!"
    assert order_id or orig_client_order_id, "either order_id or orig_client_order_id must be not None!"

    method = "DELETE"
    params = {
      'symbol': symbol,
      'orderId': order_id,
      'origClientOrderId': orig_client_order_id,
    }
    self._path = "/fapi/v1/order"

    response = self._query.query(method=method, path=self._path, params=params)
    return response.json()

  def get_order(self, symbol: str, order_id: int = None, orig_client_order_id: str = None):
    assert symbol, "symbol must be not None and not empty!"
    assert order_id or orig_client_order_id, "either order_id or orig_client_order_id must be not None!"

    method = "GET"
    params = {
      'symbol': symbol,
      'orderId': order_id,
      'origClientOrderId': orig_client_order_id,
    }
    self._path = "/fapi/v1/order"

    response = self._query.query(method=method, path=self._path, params=params)
    return response.json()

  def get_all_order(self, symbol: str):
    assert symbol, "symbol must be not None and not empty!"

    method = "GET"
    params = {
      'symbol': symbol,
    }
    self._path = "/fapi/v1/allOrders"

    response = self._query.query(method=method, path=self._path, params=params)
    return response.json()

  def get_open_order(self, symbol: str = None):
    method = "GET"
    params = {
      'symbol': symbol,
    }
    self._path = "/fapi/v1/openOrders"

    response = self._query.query(method=method, path=self._path, params=params)
    return response.json()

# api doc url
# https://apollox-finance.gitbook.io/apollox-finance/api/api-documentation

if __name__ == "__main__":
  key_path = sys.argv[1]
  
  apollox = ApolloxPrivateClient(key_path)
  info = apollox.get_open_order(symbol="BTCUSDT")
  # info = apollox.cancel_order("BTCUSDT", "12345")
  # info = apollox.submit_order("BTCUSDT", Side.SELL, Type.LIMIT, TimeInForce.GTC, "0.001", "1000000")
  print(json.dumps(info, indent=2))
